using System;
using System.Collections.Generic;
using System.Text;

using System.IO;
using SBW;
using SBMLExtension.LayoutExtension;
using System.Drawing;

namespace Athena.IO
{
    public class SBMLWriter : IModelWriter
    {
        private bool _WriteLayout = true;
        public bool WriteLayout
        {
            get { return _WriteLayout; }
            set { _WriteLayout = value; }
        }
        /// <summary>
        /// Initializes a new instance of the SBMLWriter class.
        /// </summary>
        public SBMLWriter(System.IO.Stream oStream)
        {
            _oStream = oStream;
        }

        private string GetJarnac(Model oModel)
        {
            MemoryStream oStream = new MemoryStream();
            Athena.IO.JarnacWriter oWriter = new Athena.IO.JarnacWriter(oStream);
            oWriter.WriteModel(oModel);
            oStream.Flush();
            oStream.Seek(0, SeekOrigin.Begin);
            StreamReader oReader = new StreamReader(oStream);
            return oReader.ReadToEnd();
        }

        public void WriteModelFromJarnac(string sJarnac)
        {
            string sSBML = ConvertJarnac(sJarnac);
            StreamWriter oWriter = new StreamWriter(_oStream);
            oWriter.WriteLine(sSBML);
            oWriter.Flush();
        }

        public override void WriteModel(System.IO.Stream oTargetStream, Model oModel)
        {            
            _oModel = oModel;
            _oStream = oTargetStream;

            string sJarnac = GetJarnac(oModel);
            string sSBML = ConvertJarnac(sJarnac);
            StreamWriter oWriter = new StreamWriter(oTargetStream);
            oWriter.WriteLine(sSBML);
            oWriter.Flush();
        }

        private string ConvertJarnac(string sJarnac)
        {
            string sSBML = "";

            try
            {
                LowLevel.SBWConnect();
                Module oModule = new Module("JarnacLiteConsole");
                Service oService = oModule.getService("translator");
                sJarnac = sJarnac.Replace("Time", "time");
                sSBML = oService.getMethod("string translateSBML(string)").Call(sJarnac).getString();
                LowLevel.SBWDisconnect();
            }
            catch (Exception)
            {
                ///
            }

            try
            {
                sSBML = ConvertLayout(sSBML);
            }
            catch
            {
                // don't absolutely need layout ... 
            }

            return sSBML;
        }

        private string ConvertLayout(string sSBML)
        {
            RectangleF oRect = Utility.GetBounds(_oModel.Drawables);
            Layout oLayout = new Layout("Athena_0", new double[] { oRect.Width + oRect.Left, oRect.Height + oRect.Top});
            SBMLExtension.Util.Layouts.Add(oLayout);
            Layout.CurrentLayout = oLayout;
            
            oLayout.EmlDefault = new SBMLExtension.EmlRenderExtension.RenderInformation();
            oLayout.EmlDefault.ID = "Athena_0_RenderStyle";
            oLayout.EmlDefault.ProgramName = "Athena";
            oLayout.EmlDefault.ProgramVersion = "1.0";

            oLayout._EmlRenderInformation.Add(oLayout.EmlDefault);

            oLayout.EmlDefault.LineEndings.Add(SBMLExtension.EmlRenderExtension.RenderInformation.CreateDefaultProduct("product", 
                oLayout.EmlDefault.AddColorDefinition(Color.Black), "1.0"));
            oLayout.EmlDefault.LineEndings.Add(SBMLExtension.EmlRenderExtension.RenderInformation.CreateDefaultActivator("activator", 
                oLayout.EmlDefault.AddColorDefinition(Color.Black), "1.0"));
            oLayout.EmlDefault.LineEndings.Add(SBMLExtension.EmlRenderExtension.RenderInformation.CreateDefaultModifier("modifier",
                            oLayout.EmlDefault.AddColorDefinition(Color.Black), "1.0"));
            oLayout.EmlDefault.LineEndings.Add(SBMLExtension.EmlRenderExtension.RenderInformation.CreateDefaultInhibitor("inhibitor",
                oLayout.EmlDefault.AddColorDefinition(Color.Black), "1.0"));

            SBMLExtension.EmlRenderExtension.Style oProduct = new SBMLExtension.EmlRenderExtension.Style();
            oProduct.RoleList = "product sideproduct";
            oProduct.TypeList = "product sideproduct";
            oProduct.Group = new SBMLExtension.EmlRenderExtension.Group();
            oProduct.Group.EndHead = "product";
            oProduct.Group.Stroke = oLayout.EmlDefault.AddColorDefinition(Color.Black);
            oProduct.Group.StrokeWidth = "2.0";
            oLayout.EmlDefault.Styles.Add(oProduct);

            int nCount = 0;
            foreach (Athena.Objects.IDrawable drawable in _oModel.Drawables)
            {
                if (!(drawable is Objects.BezierConnector))
                {
                    SBMLExtension.EmlRenderExtension.LocalStyle oStyle = drawable.ToStyle(oLayout.EmlDefault);
                    oLayout.SpeciesGlyphs.Add(new SpeciesGlyph("glyph_" + nCount, drawable.GlobalName,
                        new SBMLExtension.LayoutExtension.Point(drawable.Location).toDoubleArray(),
                        new SBMLExtension.LayoutExtension.Dimension(drawable.Dimensions).toDoubleArray()));

                    if (oStyle != null)
                    {
                        oStyle.IdList = "glyph_" + nCount;
                        oLayout.EmlDefault.Styles.Add(oStyle);
                    }

                    //if (!string.IsNullOrEmpty(drawable.Label))
                    //{
                    //    oLayout.TextGlyphs.Add(new TextGlyph("text_" + nCount, "glyph_" + nCount, drawable.Label,
                    //        new SBMLExtension.LayoutExtension.Point(drawable.Location).toDoubleArray(),
                    //        new SBMLExtension.LayoutExtension.Dimension(drawable.Dimensions).toDoubleArray()));
                        
                    //}

                    nCount++;
                }
                else
                {
                    // i have no idea what to do with them
                    Objects.BezierConnector bezierConnector = (Objects.BezierConnector)drawable;

                    SBMLExtension.LayoutExtension.ReactionGlyph oReaction = bezierConnector.ToGlyph(oLayout);
                    oLayout.ReactionGlyphs.Add(oReaction);
                    
                    // ok ... lets create different local styles for each type, product, activator, inhibitor, normal
                    // and then assign species references as we go along, that ought to work
                    SBMLExtension.EmlRenderExtension.LocalStyle oStyle = drawable.ToStyle(oLayout.EmlDefault);

                    SBMLExtension.EmlRenderExtension.LocalStyle oProductStyle = drawable.ToStyle(oLayout.EmlDefault);
                    oProductStyle.Group.EndHead = "product";
                    SBMLExtension.EmlRenderExtension.LocalStyle oActivatorStyle = drawable.ToStyle(oLayout.EmlDefault);
                    oActivatorStyle.Group.EndHead = "activator";
                    SBMLExtension.EmlRenderExtension.LocalStyle oInhibitorStyle = drawable.ToStyle(oLayout.EmlDefault);
                    oInhibitorStyle.Group.EndHead = "inhibitor";

                    if (oStyle != null) oStyle.IdList = "glyph_" + bezierConnector.GlobalName;

                    foreach (SpeciesReference oRef in oReaction.SpeciesReferences)
                    {
                        //System.Diagnostics.Debug.WriteLine(oRef.Role);
                        switch (oRef.Role)
                        {
                            case "activation":
                                if (oActivatorStyle != null) oActivatorStyle.IdList += " " + oRef.ID;
                                break;
                            case "inhibition":
                                if (oInhibitorStyle!= null) oInhibitorStyle.IdList += " " + oRef.ID;
                                break;
                            case "product":
                                if (oProductStyle != null) oProductStyle.IdList += " " + oRef.ID;
                                break;
                            default:
                                if (oStyle != null) oStyle.IdList += " " + oRef.ID;
                                break;

                        }
                        
                    }


                    if (oStyle != null && !string.IsNullOrEmpty(oStyle.IdList.Trim())) oLayout.EmlDefault.Styles.Add(oStyle);
                    if (oProductStyle != null && !string.IsNullOrEmpty(oProductStyle.IdList.Trim())) oLayout.EmlDefault.Styles.Add(oProductStyle);
                    if (oActivatorStyle != null && !string.IsNullOrEmpty(oActivatorStyle.IdList.Trim())) oLayout.EmlDefault.Styles.Add(oActivatorStyle);
                    if (oInhibitorStyle != null && !string.IsNullOrEmpty(oInhibitorStyle.IdList.Trim())) oLayout.EmlDefault.Styles.Add(oInhibitorStyle);

                    
                }
            }

            if (!string.IsNullOrEmpty(sSBML) && _WriteLayout)
            {

                SBMLExtension.Util.readLayout(sSBML);
                oLayout.CalculateDimensions();
                SBMLExtension.Util.Layouts.Add(oLayout);                
                sSBML = SBMLExtension.Util.writeLayout(oLayout);
            }

            return sSBML;
        }

    }
}
